﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Diagnostics;
using System.Threading.Tasks;
using JAAM.RPC;
using TestService_FS;


namespace TestServer_Console
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "";
            do
            {
                input = PrintOptions();
                if (string.IsNullOrWhiteSpace(input))
                {
                    BenchmarkSyncIBaseline();
                    //BenchmarkParallelIBaseline();
                    BenchmarkSyncDIBaseline();
                    //BenchmarkParallelDIBaseline();
                    BenchmarkSync();

                    BenchmarkSync_byIdx();
                    //BenchmarkBatches();
                    //BenchmarkAsync(615, 1);
                }
                //else if (input.StartsWith("C", StringComparison.CurrentCultureIgnoreCase))
                //    ConsoleInput();
                else
                    PrintOptions();
            } while (input != "x");
        }

        private static void BenchmarkParallelDIBaseline()
        {
            Delegate d = new Func<double, double, double>((arg1, arg2) => arg1 + arg2);
            Console.WriteLine("Starting Parallel Baseline DI benchmark");

            var cnt = 50;
            var iterations = 8;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                var sw = Stopwatch.StartNew();
                Parallel.For(0, cnt, (x) =>
                {
                    d.DynamicInvoke(3.14159 as object, 1.27658 as object);
                });
                sw.Stop();
                Console.WriteLine("processed {0} DynamicInvoke in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished Parallel Baseline DI benchmark...");
        }

        private static void BenchmarkSyncDIBaseline()
        {
            Delegate d = new Func<string, string>((arg1) => arg1);
            Console.WriteLine("Starting Sync Baseline DyanmicInvoke benchmark");

            var cnt = 50;
            var iterations = 8;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                var sw = Stopwatch.StartNew();
                for(int i =0;i<cnt;i++)               
                {
                    (d).DynamicInvoke("Whats up Yo!");
                };
                sw.Stop();
                Console.WriteLine("processed {0} DyanmicInvoke  in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished Sync Baseline DyanmicInvoke  benchmark...");
        }

        public static T cast<T>(object o)
        {
            return (T) o;
        }
        private static void BenchmarkParallelIBaseline()
        {
            var d = new Func<double, double, double>((arg1, arg2) => arg1 + arg2);
            Console.WriteLine("Starting Parallel Baseline I benchmark");

            var cnt = 50;
            var iterations = 8;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                var sw = Stopwatch.StartNew();
                Parallel.For(0, cnt, (x) =>
                {
                    d.Invoke(cast<double>((object)3.14159),cast<double>((object).27658));
                });
                sw.Stop();
                Console.WriteLine("processed {0} Invoke in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished Parallel Baseline I benchmark...");
        }

        private static void BenchmarkSyncIBaseline()
        {
            var d = new Func<double, double, double>((arg1, arg2) => arg1 + arg2);
            Console.WriteLine("Starting Sync Baseline iNVOKE benchmark");

            var cnt = 50;
            var iterations = 8;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                var sw = Stopwatch.StartNew();
                for (int i = 0; i < cnt; i++)
                {
                    d(3.14159, 1.27658);
                };
                sw.Stop();
                Console.WriteLine("processed {0} Invoke in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished Sync Baseline Invoke benchmark...");
        }
        private static string PrintOptions()
        {
            Console.WriteLine("Hit Enter to run benchmark");
            Console.WriteLine("'c' to start reading console input");
            Console.WriteLine("'x' to exit");
            return Console.ReadLine();
        }

        //private static void ConsoleInput()
        //{
        //    for (string line = Console.ReadLine(); !string.IsNullOrEmpty(line); line = Console.ReadLine())
        //    {
        //        var result = service.Dispatcher.Invoke(new RpcRequest("add", new[] {3.14159,1.27658}, 1));
        //        if(result.Error!=null)
        //            Console.WriteLine(result.Error.InnerException.ToString());
        //        else
        //        {
        //            Console.WriteLine(result.Result);
        //        }
        //    }
        //}

        private static volatile int ctr;
        private static void BenchmarkSync()
        {
            Console.WriteLine("Starting benchmark");
            var service = new RPCService();

            service.AddToServiceCS("internal.echo","str", (string str) => str );


            var cnt = 50;
            var iterations = 8;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                //var item1 = new RpcRequest ("internal.echo", new[] { "Whats up YO!" }, 1 );
                //var item2 = new RpcRequest ("add", new[] { 3.14159, 1.26574 }, 2 );
                var item3 = new RpcRequest<string>("internal.echo", "Whats up Yo!", 1);
                //var item4 = new RpcRequest<Tuple<double,double>>("add", new Tuple<Double,Double>(3.2342,1.2342), 1);
                GC.Collect();
                var sw = Stopwatch.StartNew();
                for (int i = 0; i < cnt; i++)
                {
                        //service.Dispatcher.Dispatch(item1);
                        //service.Dispatcher.Dispatch(item2);
                        service.Invoke(item3);
                        //service.Dispatcher.Dispatch(item4);
                }
                sw.Stop();
                Console.WriteLine("processed {0} rpc in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished benchmark...");
        }
        private static void BenchmarkSync_byIdx()
        {
            Console.WriteLine("Starting benchmark by iDx");
            var service = new RPCService();

            service.AddToServiceCS("internal.echo", "str", (string str) => str);


            var cnt = 50;
            var iterations = 9;
            for (int iteration = 1; iteration <= iterations; iteration++)
            {
                cnt *= iteration;
                //var item1 = new RpcRequest ("internal.echo", new[] { "Whats up YO!" }, 1 );
                //var item2 = new RpcRequest ("add", new[] { 3.14159, 1.26574 }, 2 );
                var item3 = new RpcRequest<string>("internal.echo", "Whats up Yo!", 1);
                //var item4 = new RpcRequest<Tuple<double,double>>("add", new Tuple<Double,Double>(3.2342,1.2342), 1);
                GC.Collect();
                var sw = Stopwatch.StartNew();
                for (int i = 0; i < cnt; i++)
                {
                    //service.Dispatcher.Dispatch(item1);
                    //service.Dispatcher.Dispatch(item2);
                    service.Invoke(0,item3);
                    //service.Dispatcher.Dispatch(item4);
                }
                sw.Stop();
                Console.WriteLine("processed {0} rpc in {1}ms for {2} rpc/sec", cnt, sw.ElapsedMilliseconds, (double)cnt * 1000d / sw.ElapsedMilliseconds);
            }
            Console.WriteLine("Finished benchmark by Idx...");
        }
        //private static Tuple<double,int> BenchmarkAsync(int batchSize, int depth)
        //{
        //    Console.WriteLine("Starting benchmark async");
        //    var growSize = 5;
        //    var iterations = 7;
        //    var best = 0.0;
        //    for (int cnt = 1; cnt <= iterations; cnt++)
        //    {
        //        var items = Enumerable.Repeat(new RpcRequest ("internal.echo", new[] { "Whats up YO!" },  1 ), batchSize).ToList();
        //        var sw = Stopwatch.StartNew();
        //        var loops = cnt*cnt*50;
        //        for (int j = 0; j < loops; j += 1)
        //        {
        //            service.Dispatcher.Invoke(items);
        //        }
        //        sw.Stop();
        //        var speed = (double) loops*batchSize*1000d/sw.ElapsedMilliseconds;
        //        Console.WriteLine("processed {0} rpc in {1}ms for {2} rpc/sec", loops * batchSize, sw.ElapsedMilliseconds, (double)loops * batchSize * 1000d / sw.ElapsedMilliseconds);
        //        if (speed > best)
        //            best = speed;
        //    }

        //    Console.WriteLine("Finished benchmark async... ");
        //    var myResult = new Tuple<double, int>(best, batchSize);
        //    if (depth > 0)
        //    {
        //        var higher = BenchmarkAsync(Convert.ToInt32(batchSize*1.05), 0);
        //        var lower = BenchmarkAsync(Convert.ToInt32(batchSize*.95), 0);

        //        if (higher.Item1 > myResult.Item1)
        //            myResult = higher;
        //        if (lower.Item1 > myResult.Item1)
        //            myResult = lower;

        //        myResult = BenchmarkAsync(myResult.Item2, depth-1);
        //    }
        //    Console.WriteLine("Best: Speed: {0}/per sec, size: {1}",myResult.Item1,myResult.Item2);
        //    return myResult;
        //}

        //private static void BenchmarkBatches()
        //{
        //    Console.WriteLine("Starting benchmark batches");

        //    var cnt = 50;
        //    const int iterations = 8;
        //    for (int iteration = 1; iteration <= iterations; iteration++)
        //    {
        //        cnt *= iteration;
        //        ctr = 0;

        //        var batch = Enumerable.Repeat(new RpcRequest ("add", new[] { 3.14159, 1.27658 }, 1 ), cnt).ToList();
        //        var sw = Stopwatch.StartNew();
        //        var presult = service.Dispatcher.InvokeBatch(batch).ToList();
        //        sw.Stop();
        //        var num = presult.Count;
        //        Console.WriteLine("processed {0} rpc in {1}ms for {2} rpc/sec", num, sw.ElapsedMilliseconds, (double)num * 1000d / sw.ElapsedMilliseconds);
        //    }


        //    Console.WriteLine("Finished benchmark batches ...");
        //}
    }

    
}
